using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Security.Cryptography;

namespace LeisureCenter.MetadataHandlers
{
    public class SHA256MaxLength : SHA256Managed
    {
        public byte[] ComputeHash(Stream inputStream, long length)
        {
            byte[] buffer1 = new byte[0x1000];
            while (true)
            {
                int num1 = inputStream.Read(buffer1, 0, Math.Min(0x1000, (int)length));
                if (num1 > 0)
                {
                    this.HashCore(buffer1, 0, num1);
                    length -= num1;
                }
                if (num1 <= 0)
                {
                    this.HashValue = this.HashFinal();
                    byte[] buffer2 = (byte[])this.HashValue.Clone();
                    this.Initialize();
                    return buffer2;
                }
            }
        }
    }

    public class SHA256FivePercent : SHA256Managed
    {
        public new byte[] ComputeHash(Stream inputStream)
        {
            byte[] buffer1 = new byte[0x1000];
            while (true)
            {
                int num1 = inputStream.Read(buffer1, 0, 0x1000);
                if (num1 > 0)
                {
                    this.HashCore(buffer1, 0, num1);
                }
                if (num1 <= 0)
                {
                    this.HashValue = this.HashFinal();
                    byte[] buffer2 = (byte[])this.HashValue.Clone();
                    this.Initialize();
                    return buffer2;
                }
                inputStream.Seek(0x1000 * 19, SeekOrigin.Current);
            }
        }
    }

    public abstract class MetadataHandler
    {
        protected string dataHash = "";

        protected static string HashToString(byte[] hash)
        {
            string hexaHash = "";
            foreach (byte b in hash)
            {
                hexaHash += String.Format("{0:x2}", b);
            }
            return hexaHash;
        }

        protected static string HashStreamFromPosition(Stream stream)
        {
            SHA256Managed sha = new SHA256Managed();
            byte[] hash = sha.ComputeHash(stream);
            return HashToString(hash);
        }

        protected static string HashStreamFromPositionLength(Stream stream, long length)
        {
            SHA256MaxLength sha = new SHA256MaxLength();
            byte[] hash = sha.ComputeHash(stream, length - stream.Position);
            return HashToString(hash);
        }

        protected static string HashStreamFromPositionFivePercent(Stream stream)
        {
            SHA256FivePercent sha = new SHA256FivePercent();
            byte[] hash = sha.ComputeHash(stream);
            return HashToString(hash);
        }

        public abstract void ReadMetadata(string fileName, Stream stream, bool computeDataHash);

        public virtual void ReadMetadata(string fileName, bool computeDataHash)
        {
            using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Delete))
            {
                ReadMetadata(fileName, fs, computeDataHash);
            }
        }

        public string DataHash
        {
            get { return this.dataHash; }
        }

        public virtual int Kind { get { return 0; } }
    }

    public abstract class AudioMetadataHandler : MetadataHandler
    {
        protected string artist = "";
        protected string album = "";
        protected int? track = null;
        protected string title = "";
        protected int? year = null;
        protected string genre = "";

        public string Artist { get { return artist; } set { artist = value; } }
        public string Album { get { return album; } set { album = value; } }
        public int? Track { get { return track; } set { track = value; } }
        public string Title { get { return title; } set { title = value; } }
        public int? Year { get { return year; } set { year = value; } }
        public string Genre { get { return genre; } set { genre = value; } }

        public override int Kind { get { return 1; } }
    }

    public enum VideoType
    {
        Other,
        Movie,
        TvShow,
        VideoClip
    }

    public abstract class VideoMetadataHandler : MetadataHandler
    {
        protected string title = "";
        protected string subtitle = "";
        protected int? number = null;
        protected int? subNumber = null;
        protected VideoType? type = null;

        public string Title { get { return title; } set { title = value; } }
        public string Subtitle { get { return subtitle; } set { subtitle = value; } }
        public int? Number { get { return number; } set { number = value; } }
        public int? SubNumber { get { return subNumber; } set { subNumber = value; } }
        public VideoType? Type { get { return type; } set { type = value; } }

        public override int Kind { get { return 2; } }
    }

    public abstract class MetadataHandlerFactory
    {
        public abstract bool AcceptMedia(string fileName, Stream stream);

        public abstract MetadataHandler CreateMetadata();
    }
}